package com.bluesky.common;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class TreeNode implements Serializable {
	private TreeNode parent;
	private List<TreeNode> children;

	public TreeNode() {
		parent = null;
		children = new ArrayList<TreeNode>();

	}

	public int getDepth() {
		if (parent == null)
			return 0;
		else
			return parent.getDepth() + 1;

	}

	public boolean isLeaf() {
		return children.isEmpty();
	}

	public boolean isRoot() {
		return parent == null;
	}

	public void addChild(int index, TreeNode node) {
		children.add(index, node);
		node.parent = this;
	}

	public void addChild(TreeNode node) {
		children.add(node);
		node.parent = this;
	}

	public void removeChild(TreeNode node) {

		if (!children.remove(node))
			throw new RuntimeException("it is not a child:" + node);

		node.parent = null;
	}

	/**
	 * remove itself from parent node.
	 */
	public void detach() {
		if (parent != null)
			parent.removeChild(this);
	}

	public TreeNode getParent() {
		return parent;
	}

	public TreeNode getRoot() {
		if (parent == null)
			return this;
		else
			return parent.getRoot();
	}

	public void setParent(TreeNode parent) {
		this.parent = parent;
	}

	public void setChildren(List<TreeNode> children) {
		this.children = children;
	}

	public List<TreeNode> getChildren() {
		return children;
	}

	public void removeAllChildren() {
		while (!getChildren().isEmpty()) {
			TreeNode tn = getChildren().get(0);
			removeChild(tn);
		}

	}

	/**
	 * replace the whole branch.
	 * @param rootOfBrach
	 */
	public void replace(TreeNode rootOfBrach) {
		if (this == rootOfBrach)
			return;

		rootOfBrach.setParent(parent);

		if (parent != null) {

			TreeNode parentNode = getParent();
			int index = parentNode.getChildren().indexOf(this);

			if (index < 0)
				throw new RuntimeException("it is not a child node.");

			parentNode.getChildren().set(index, rootOfBrach);
			rootOfBrach.setParent(parentNode);

		}
	}

	/**
	 * replace at the same index. take care of the child-parent relationship.
	 * 
	 * @param newNode
	 */
	public void replaceSingleNode(TreeNode newNode) {
		if (this == newNode)
			return;

		newNode.setParent(parent);

		if (parent != null) {

			TreeNode parentNode = getParent();
			int index = parentNode.getChildren().indexOf(this);

			if (index < 0)
				throw new RuntimeException("it is not a child node.");

			parentNode.getChildren().set(index, newNode);
			newNode.setParent(parentNode);

		}

		newNode.getChildren().clear();
		newNode.getChildren().addAll(getChildren());
		for (TreeNode tn : newNode.getChildren()) {
			tn.setParent(newNode);
		}

		newNode.checkConsistency();
	}

	public void copy(TreeNode src) {
		// parent = src.parent;

		// children = src.children;
	}

	protected void checkConsistency() {
		TreeNode parentNode = getParent();
		if (parentNode != null) {
			int index = parentNode.getChildren().indexOf(this);

			if (index < 0)
				throw new RuntimeException(
						"checkConsistency fail,it is not a child node.");
		}
		for (TreeNode tn : getChildren()) {
			if (tn.getParent() != this)
				throw new RuntimeException(
						"checkConsistency fail,it is not a child node.");
		}
	}

}
